//*************************************************************************************
// Indexing functions used for mapping given bitboard position to the arrays index
// in the sub-database slice
//*************************************************************************************

#include "Stdafx.h"	
#include "Engine.h"

//*************************************************************************************
// 32-bit indexing functions
//*************************************************************************************

void BitBoardToIndex(BitBoard *p, int64 *index)
{
	// variables
	int bm, bk, wm, wk;
	int bmrank=0;
	int wmrank=0;

	int i;
	uint32 x,y;
	int64 bmindex=0,bkindex=0,wmindex=0,wkindex=0;
	int64 wmrange=1, bmrange=1, wkrange=1;
	int64 posindex=0;
	
	// calculate figure counts and heighest rank
	wm = BitCount(p->wm);
	if(wm)
		wmrank = MSB(p->wm)/4;
	wk = BitCount(p->wk);
	bm = BitCount(p->bm);
	if(bm)
		bmrank = (31-LSB(p->bm))/4;
		
	bk = BitCount(p->bk);

	// calculate indexes
	i=1;
	y=p->wm;
	while(y)
		{
		x=LSB(y);
		y=y^(1<<x);
		wmindex+=BinomCoef[x][i];
		i++;
		}

	i=1;
	y=p->bm;
	while(y)
		{
		x=MSB(y);
		y=y^(1<<x);
		x=31-x;
		bmindex+=BinomCoef[x][i];
		i++;
		}

	i=1;
	y=p->wk;
	while(y)
		{
		x=LSB(y);
		y=y^(1<<x);
		// next line is the count of men on squares 0....x-1, as x-1 of a 0000010000000 number is 0000000111111111
		x-=BitCount((p->wm|p->bm)&((1<<x)-1)); 
		wkindex+=BinomCoef[x][i];
		i++;
		}

	i=1; 
	y=p->bk;
	while(y)
		{
		x=LSB(y);
		y^=(1<<x);
		x-=BitCount((p->wm|p->wk|p->bm) & ( (1<<x)-1 ) );
		bkindex += BinomCoef[x][i];
		i++;
		}

	if(wm)
		wmrange = BinomCoef[4*(wmrank+1)][wm] - BinomCoef[4*wmrank][wm];
	if(bm)
		bmrange = BinomCoef[4*(bmrank+1)][bm] - BinomCoef[4*bmrank][bm];
	if(wk)
		wkrange = BinomCoef[32-wm-bm][wk];

	if(wmrank)
		wmindex -= BinomCoef[4*wmrank][wm];
	if(bmrank)
		bmindex -= BinomCoef[4*bmrank][bm];

	posindex = wmindex + bmindex*wmrange + wkindex*wmrange*bmrange + bkindex*wmrange*bmrange*wkrange;


	*index = posindex;	
}


void IndexToBitBoard(int64 index, BitBoard *p, int wm, int wk, int bm, int bk, int wmrank,  int bmrank)
{
	// reverse the BitBoard to index thing

	int64 wmindex=0, wkindex=0, bmindex=0, bkindex=0;
	int64 wmrange=1, bmrange=1, wkrange=1;
	
	int64 multiplier;
	uint32 square_one=1;
	uint32 occupied;
	int i,j,k,f;
	int bkpos[MAXPIECE],wkpos[MAXPIECE];
	
	p->wm = 0;
	p->wk = 0;
	p->bm = 0;
	p->bk = 0;
	

	// extract the indexes for the piece types from the total index:
	// get multiplier for wkindex:
	if(wm)
		wmrange = BinomCoef[4*(wmrank+1)][wm] - BinomCoef[4*wmrank][wm];
		
	if(bm)
		bmrange = BinomCoef[4*(bmrank+1)][bm] - BinomCoef[4*bmrank][bm];
		
	if(wk)
		wkrange = BinomCoef[32-wm-bm][wk];
		
	multiplier = wmrange*bmrange*wkrange;
	bkindex = index / multiplier;
	index -= bkindex*multiplier;

	multiplier = wmrange*bmrange;
	wkindex = index / multiplier;
	index -= wkindex*multiplier;

	bmindex = index / wmrange;
	index -= bmindex*wmrange;

	wmindex = index;
	
	// add the rank index
	if(wm)
		wmindex += BinomCoef[4*wmrank][wm];
	if(bm)
		bmindex += BinomCoef[4*bmrank][bm];

	// now that we know the index numbers, we extract the pieces 
	// extract black men directly
	i=27;
	j=wm;
	while(j)
		{
		while(BinomCoefTrans[j][i]>wmindex)
			i--;
		wmindex-=BinomCoefTrans[j][i];
		p->wm |= square_one<<i;
		j--;
		}

	// extract white men directly
	i=27;
	j=bm;
	while(j)
		{
		while(BinomCoefTrans[j][i]>bmindex)
			i--;
		bmindex -= BinomCoefTrans[j][i];
		p->bm |= square_one<<(31-i);
		j--;
		}

	// extract BitBoards of black kings
	i=31;
	for(j=wk;j>0;j--)
		{
		while(BinomCoefTrans[j][i]>wkindex)
			i--;
		wkindex-=BinomCoefTrans[j][i];
		wkpos[j-1]=i;
		}
	
	// extract BitBoards of white kings
	i=31;
	for(j=bk;j>0;j--)
		{
		while(BinomCoefTrans[j][i]>bkindex)
			i--;
		bkindex-=BinomCoefTrans[j][i];
		bkpos[j-1]=i;
		}
	
	// now, put black kings on the board. we know: bkpos[0]...bkpos[bk-1] is ordered
	// with bkpos[0] being the smallest one, same goes for wkpos;

	occupied = p->wm | p->bm;
	k=0;
	f=0;
	for(i=0;i<32,k<wk;i++)
		{
		if(occupied & (square_one<<i))
			continue;
		if(wkpos[k] == f)
			{
			p->wk|=(square_one<<i);
			k++;
			}
		f++;
		}
	
	occupied = p->wm|p->bm|p->wk;
	k=0;
	f=0;
	for(i=0;i<32,k<bk;i++)
		{
		if(occupied & (square_one<<i))
			continue;
		if(bkpos[k] == f)
			{
			p->bk|=(square_one<<i);
			k++;
			}
		f++;
		}	
}

//*************************************************************************************
// 64-bit indexing functions
//*************************************************************************************

template<int BitsPerRow, int MaxField>
void BitBoardToIndex64(BitBoard64 *p, int64 *index)
{
	// variables
	int bm, bk, wm, wk;
	int bmrank=0;
	int wmrank=0;

	int i;
	uint64 x,y;
	int64 bmindex=0,bkindex=0,wmindex=0,wkindex=0;
	int64 wmrange=1, bmrange=1, wkrange=1;
	int64 posindex=0;
	
	// calculate figure counts and heighest rank
	wm = BitCount64(p->wm);
	if(wm)
		wmrank = MSB64(p->wm)/BitsPerRow;
	wk = BitCount64(p->wk);
	bm = BitCount64(p->bm);
	if(bm)
		bmrank = (MaxField-LSB64(p->bm))/BitsPerRow;
		
	bk = BitCount64(p->bk);

	// calculate indexes
	i=1;
	y=p->wm;
	while(y)
		{
		x=LSB64(y);
		y=y^(1ull<<x);
		wmindex+=BinomCoef[x][i];
		i++;
		}

	i=1;
	y=p->bm;
	while(y)
		{
		x=MSB64(y);
		y=y^(1ull<<x);
		x=MaxField-x;
		bmindex+=BinomCoef[x][i];
		i++;
		}

	i=1;
	y=p->wk;
	while(y)
		{
		x=LSB64(y);
		y=y^(1ull<<x);
		// next line is the count of men on squares 0....x-1, as x-1 of a 0000010000000 number is 0000000111111111
		x-=BitCount64((p->wm|p->bm)&((1ull<<x)-1ull)); 
		wkindex+=BinomCoef[x][i];
		i++;
		}

	i=1; 
	y=p->bk;
	while(y)
		{
		x=LSB64(y);
		y^=(1ull<<x);
		x-=BitCount64((p->wm|p->wk|p->bm) & ( (1ull<<x)-1ull ) );
		bkindex += BinomCoef[x][i];
		i++;
		}

	if(wm)
		wmrange = BinomCoef[BitsPerRow*(wmrank+1)][wm] - BinomCoef[BitsPerRow*wmrank][wm];
	if(bm)
		bmrange = BinomCoef[BitsPerRow*(bmrank+1)][bm] - BinomCoef[BitsPerRow*bmrank][bm];
	if(wk)
		wkrange = BinomCoef[MaxField+1-wm-bm][wk];

	if(wmrank)
		wmindex -= BinomCoef[BitsPerRow*wmrank][wm];
	if(bmrank)
		bmindex -= BinomCoef[BitsPerRow*bmrank][bm];

	posindex = wmindex + bmindex*wmrange + wkindex*wmrange*bmrange + bkindex*wmrange*bmrange*wkrange;


	*index = posindex;	
}


template<int BitsPerRow, int MaxField>
void IndexToBitBoard64(int64 index, BitBoard64 *p, int wm, int wk, int bm, int bk, int wmrank,  int bmrank)
{
	// reverse the BitBoard to index thing

	int64 wmindex=0, wkindex=0, bmindex=0, bkindex=0;
	int64 wmrange=1, bmrange=1, wkrange=1;
	
	int64 multiplier;
	uint64 square_one=1;
	uint64 occupied;
	int i,j,k,f;
	int bkpos[MAXPIECE],wkpos[MAXPIECE];
	
	p->wm = 0;
	p->wk = 0;
	p->bm = 0;
	p->bk = 0;
	

	// extract the indexes for the piece types from the total index:
	// get multiplier for wkindex:
	if(wm)
		wmrange = BinomCoef[BitsPerRow*(wmrank+1)][wm] - BinomCoef[BitsPerRow*wmrank][wm];
		
	if(bm)
		bmrange = BinomCoef[BitsPerRow*(bmrank+1)][bm] - BinomCoef[BitsPerRow*bmrank][bm];
		
	if(wk)
		wkrange = BinomCoef[MaxField+1-wm-bm][wk];
		
	multiplier = wmrange*bmrange*wkrange;
	bkindex = index / multiplier;
	index -= bkindex*multiplier;

	multiplier = wmrange*bmrange;
	wkindex = index / multiplier;
	index -= wkindex*multiplier;

	bmindex = index / wmrange;
	index -= bmindex*wmrange;

	wmindex = index;
	
	// add the rank index
	if(wm)
		wmindex += BinomCoef[BitsPerRow*wmrank][wm];
	if(bm)
		bmindex += BinomCoef[BitsPerRow*bmrank][bm];

	// now that we know the index numbers, we extract the pieces 
	// extract black men directly
	i=MaxField - BitsPerRow;
	j=wm;
	while(j)
		{
		while(BinomCoefTrans[j][i]>wmindex)
			i--;
		wmindex-=BinomCoefTrans[j][i];
		p->wm |= square_one<<i;
		j--;
		}

	// extract white men directly
	i=MaxField - BitsPerRow;
	j=bm;
	while(j)
		{
		while(BinomCoefTrans[j][i]>bmindex)
			i--;
		bmindex -= BinomCoefTrans[j][i];
		p->bm |= square_one<<(MaxField-i);
		j--;
		}

	// extract BitBoards of black kings
	i=MaxField;
	for(j=wk;j>0;j--)
		{
		while(BinomCoefTrans[j][i]>wkindex)
			i--;
		wkindex-=BinomCoefTrans[j][i];
		wkpos[j-1]=i;
		}
	
	// extract BitBoards of white kings
	i=MaxField;
	for(j=bk;j>0;j--)
		{
		while(BinomCoefTrans[j][i]>bkindex)
			i--;
		bkindex-=BinomCoefTrans[j][i];
		bkpos[j-1]=i;
		}
	
	// now, put black kings on the board. we know: bkpos[0]...bkpos[bk-1] is ordered
	// with bkpos[0] being the smallest one, same goes for wkpos;

	occupied = p->wm | p->bm;
	k=0;
	f=0;
	for(i=0;i<MaxField+1,k<wk;i++)
		{
		if(occupied & (square_one<<i))
			continue;
		if(wkpos[k] == f)
			{
			p->wk|=(square_one<<i);
			k++;
			}
		f++;
		}
	
	occupied = p->wm|p->bm|p->wk;
	k=0;
	f=0;
	for(i=0;i<MaxField+1,k<bk;i++)
	{
		if(occupied & (square_one<<i))
			continue;
		if(bkpos[k] == f)
		{
			p->bk|=(square_one<<i);
			k++;
		}
		f++;
	}	
}

//*************************************************************************************
// Templated bitboard size switching
//*************************************************************************************

// BitBoard => Index
template<typename BB> void BitBoardToIndexXX(BB* p, int64* index)
{
	assert(false);
}

template<> void BitBoardToIndexXX<BitBoard>(BitBoard* p, int64* index)
{
	BitBoardToIndex(p, index);
}

template<> void BitBoardToIndexXX<BitBoard64>(BitBoard64* p, int64* index)
{
	BitBoardToIndex64<5, 49>(p, index);
}


// Index => BitBoard
template<typename BB, int BitsPerRow, int MaxField> 
void IndexToBitBoardXX(int64 index, BB *p, int wm, int wk, int bm, int bk, int wmrank,  int bmrank)
{
	assert(false);
}

template<> void IndexToBitBoardXX<BitBoard>(int64 index, BitBoard *p, 
											int wm, int wk, int bm, int bk, int wmrank,  int bmrank)
{
	IndexToBitBoard(index, p, wm, wk, bm, bk, wmrank, bmrank);
}

template<> void IndexToBitBoardXX<BitBoard64>(int64 index, BitBoard64 *p, 
											int wm, int wk, int bm, int bk, int wmrank,  int bmrank)
{
	IndexToBitBoard64<5, 49>(index, p, wm, wk, bm, bk, wmrank, bmrank);
}
